package com.bzg.cglib;

import org.springframework.cglib.core.DebuggingClassWriter;
import org.springframework.cglib.proxy.*;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

// cglib不能多次代理，也就是对cglib代理对象再代理
// 本质是cglib会插入final方法，使得第二次代理时，代理类中出现2多个相同的final newInstance方法，一个是父类继承过来的，一个是自己插入的
// https://blog.51cto.com/javastack/3243714
/**
 * 1、Enhancer在使用后如果重新设置callback，代理类不会变，但callback会替换之前的
 * 2、如果是父类或接口替换了，那么代理类也就变了
 * 3、除了静态方法、私有方法、final方法不重写。桥接方法也不重写，试想一下桥接方法要被代理那么就会导致目标方法代理失效
 * 但注意一点：在cglib3.1版本时有桥接方法会直接报错(亲身测试)。但3.3版本(博客上说的，自己没试过)和老版本不会。
 * spring由于是直接复制了cglib相关代码(所以不受cglib版本影响)，所以采用spring里面的cglib代码去代理具有桥接方法的类也不会报错
 * 但桥接方法不会被重写，因此代理类在调用桥接方法时直接就是直接代理类的继承父类的桥接方法
 *
 * //代理类不会生成构造函数，所以他仅有一个默认的无参构造
 * */
public class CglibStyle {

	public static void main(String[] args) {
		System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,"D:");
		Enhancer enhancer = new Enhancer();
		enhancer.setInterfaces(new Class[]{UserService.class});
		enhancer.setSuperclass(UserServiceImpl.class);
		enhancer.setCallbackFilter(new CallbackFilter() {
			@Override
			public int accept(Method method) {
				if(method.getName().equals("test")) {
					return 0;
				}else if(method.getName().equals("testFixed")) {
					return 0;
				}
				return 1;
			}
		});
		enhancer.setCallbackTypes(new Class[]{Type1.class,NoOp.class});
		enhancer.setCallbacks(new Callback[]{new Type1(),new NoOp(){}});
		UserService o = (UserService)enhancer.create();
		System.out.println(o.testFixed());
	}
}
class Type0 implements MethodInterceptor {
	/**
	 * @param o 代理对象
	 * @param method 目标方法
	 * @param objects 参数
	 * @param methodProxy 基于索引的方法
	 * */
	@Override
	public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
		System.out.println(111);
		methodProxy.invokeSuper(o,objects);
		return methodProxy.invoke(new UserServiceImpl(),objects);
	}
}

class Type1 implements FixedValue {

	@Override
	public Object loadObject() throws Exception {
		return "fix";
	}
}
